/*! Copyright (c) 2011 Piotr Rochala (http://rocha.la)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Version: 1.0.6
 *
 */
(function ($) {

    jQuery.fn.extend({
        slimScrollCustom: function (options) {

            var defaults = {
                wheelStep: 20,
                width: 'auto',
                height: '250px',
                size: '7px',
                color: '#000',
                position: 'right',
                distance: '1px',
                start: 'top',
                opacity: .4,
                alwaysVisible: false,
                disableFadeOut: false,
                railVisible: false,
                railColor: '#333',
                railOpacity: '0.2',
                railClass: 'slimScrollRail',
                barClass: 'slimScrollBar',
                wrapperClass: 'slimScrollDiv',
                allowPageScroll: false,
                scroll: 0,
                touchScrollStep: 200,
                largeSize: '9px'
            };

            var o = $.extend(defaults, options);

            // do it for every element that matches selector
            this.each(function () {

                var isOverPanel, isOverBar, isDragg, queueHide, touchDif,
        barHeight, percentScroll, lastScroll,
        divS = '<div></div>',
        minBarHeight = 30,
        releaseScroll = false;

                // used in event handlers and for better minification
                var me = $(this);

                // ensure we are not binding it again
                if (me.parent().hasClass(o.wrapperClass)) {
                    // start from last bar position
                    var offset = me.scrollTop();

                    // find bar and rail
                    bar = me.parent().find("." + o.barClass);
                    rail = me.parent().find("." + o.railClass);

                    getBarHeight();

                    // check if we should scroll existing instance
                    if (options) {
                        if ('scrollTo' in options) {
                            // jump to a static point
                            offset = parseInt(o.scrollTo);
                        }
                        else if ('scrollBy' in options) {
                            // jump by value pixels
                            offset += parseInt(o.scrollBy);
                        }

                        // scroll content by the given offset
                        scrollContent(offset, false, true);
                    }

                    return;
                }

                // optionally set height to the parent's height
                o.height = (o.height == 'auto') ? me.parent().innerHeight() : o.height;
                // Register wapper class
                me.parent().addClass(o.wrapperClass);
                // wrap content - wrap is current parent
                //                var wrapper = $(me).parent()
                //          .addClass(o.wrapperClass)
                //          .css({
                //              //position: 'relative',
                //              overflow: 'hidden',
                //              width: o.width,
                //              height: o.height
                //          });

                // update style for the div
                //                me.css({
                //                    overflow: 'hidden',
                //                    width: o.width,
                //                    height: o.height
                //                });

                // create scrollbar rail
                var rail = $(divS)
          .addClass(o.railClass)
          .css({
              width: o.size,
              height: '100%',
              position: 'absolute',
              top: 0,
              display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none',
              'border-radius': o.size,
              background: o.railColor,
              opacity: o.railOpacity,
              zIndex: 90
          });

                // create scrollbar
                var bar = $(divS)
          .addClass(o.barClass)
          .css({
              background: o.color,
              width: o.size,
              position: 'absolute',
              top: 0,
              opacity: o.opacity,
              display: o.alwaysVisible ? 'block' : 'none',
              'border-radius': o.size,
              BorderRadius: o.size,
              MozBorderRadius: o.size,
              WebkitBorderRadius: o.size,
              zIndex: 99
          });

                // set position
                var posCss = (o.position == 'right') ? { right: o.distance} : { left: o.distance };
                rail.css(posCss);
                bar.css(posCss);

                // wrap it
                //me.wrap(wrapper);

                // append to parent div
                me.parent().append(bar);
                me.parent().append(rail);

                // make it draggable
                bar.draggable({
                    axis: 'y',
                    containment: 'parent',
                    start: function () { isDragg = true; },
                    stop: function () { isDragg = false; hideBar(); },
                    drag: function (e) {
                        // scroll content
                        scrollContent(0, $(this).position().top, false);
                    }
                });
                bar.mousedown(function () { isMouseDown = true; });
                $(document).mouseup(function () { isMouseDown = false; zoomOut(); });

                // on rail over
                rail.hover(function (e) {
                    showBar();
                    zoomIn();
                    e.stopPropagation();
                }, function () {
                    zoomOut();
                    hideBar();
                });

                // on bar over
                bar.hover(function () {
                    zoomIn();
                    isOverBar = true;
                }, function () {
                    zoomOut();
                    isOverBar = false;
                });

                // show on parent mouseover
                me.hover(function () {
                    isOverPanel = true;
                    showBar();
                    hideBar();
                }, function () {
                    isOverPanel = false;
                    hideBar();
                });

                // support for mobile
                me.bind('touchstart', function (e, b) {
                    if (e.originalEvent.touches.length) {
                        // record where touch started
                        touchDif = e.originalEvent.touches[0].pageY;
                    }
                });

                me.bind('touchmove', function (e) {
                    // prevent scrolling the page
                    e.originalEvent.preventDefault();
                    if (e.originalEvent.touches.length) {
                        // see how far user swiped
                        var diff = (touchDif - e.originalEvent.touches[0].pageY) / o.touchScrollStep;
                        // scroll content
                        scrollContent(diff, true);
                    }
                });

                var _onWheel = function (e) {
                    // use mouse wheel only when mouse is over
                    if (!isOverPanel) { return; }

                    var e = e || window.event;

                    var delta = 0;
                    if (e.wheelDelta) { delta = -e.wheelDelta / 120; }
                    if (e.detail) { delta = e.detail / 3; }

                    // scroll content
                    scrollContent(delta, true);

                    // stop window scroll
                    if (e.preventDefault && !releaseScroll) { e.preventDefault(); }
                    if (!releaseScroll) { e.returnValue = false; }
                }

                function scrollContent(y, isWheel, isJump) {
                    var delta = y;
                    var maxTop = me.outerHeight() - bar.outerHeight();

                    if (isWheel) {
                        // move bar with mouse wheel
                        delta = parseInt(bar.css('top')) + y * parseInt(o.wheelStep) / 100 * bar.outerHeight();

                        // move bar, make sure it doesn't go out
                        delta = Math.min(Math.max(delta, 0), maxTop);

                        // scroll the scrollbar
                        bar.css({ top: delta + 'px' });
                    }

                    // calculate actual scroll amount
                    percentScroll = parseInt(bar.css('top')) / (me.outerHeight() - bar.outerHeight());
                    delta = percentScroll * (me[0].scrollHeight - me.outerHeight());

                    if (isJump) {
                        delta = y;
                        var offsetTop = delta / me[0].scrollHeight * me.outerHeight();
                        offsetTop = Math.min(Math.max(offsetTop, 0), maxTop);
                        bar.css({ top: offsetTop + 'px' });
                    }

                    // scroll content
                    me.scrollTop(delta);

                    // ensure bar is visible
                    showBar();

                    // trigger hide when scroll is stopped
                    hideBar();
                }

                var attachWheel = function () {
                    if (window.addEventListener) {
                        this.addEventListener('DOMMouseScroll', _onWheel, false);
                        this.addEventListener('mousewheel', _onWheel, false);
                    }
                    else {
                        document.attachEvent("onmousewheel", _onWheel)
                    }
                }

                // attach scroll events
                attachWheel();

                function getBarHeight() {
                    // calculate scrollbar height and make sure it is not too small
                    barHeight = Math.max((me.outerHeight() / me[0].scrollHeight) * me.outerHeight(), minBarHeight);
                    bar.css({ height: barHeight + 'px' });
                }

                // set up initial height
                getBarHeight();

                function showBar() {
                    // recalculate bar height
                    getBarHeight();
                    clearTimeout(queueHide);

                    // when bar reached top or bottom
                    if (percentScroll == ~ ~percentScroll) {
                        //release wheel
                        releaseScroll = o.allowPageScroll;

                        // publish approporiate event
                        if (lastScroll != percentScroll) {
                            var msg = (~ ~percentScroll == 0) ? 'top' : 'bottom';
                            me.trigger('slimscroll', msg);
                        }
                    }
                    lastScroll = percentScroll;

                    // show only when required
                    if (barHeight >= me.outerHeight()) {
                        //allow window scroll
                        releaseScroll = true;
                        return;
                    }
                    bar.stop(true, true).fadeIn('fast');
                    if (o.railVisible) { rail.stop(true, true).fadeIn('fast'); }
                }

                function hideBar() {
                    // only hide when options allow it
                    if (!o.alwaysVisible) {
                        queueHide = setTimeout(function () {
                            if (!(o.disableFadeOut && isOverPanel) && !isOverBar && !isDragg) {
                                bar.fadeOut('slow');
                                rail.fadeOut('slow');
                            }
                        }, 1000);
                    }
                }

                // ThanhDT custom
                function zoomIn() {
                    clearTimeout(queueZoom);
                    rail.animate({ "width": o.largeSize });
                    bar.animate({ "width": o.largeSize });
                }
                var queueZoom = 0, isMouseDown = false;
                function zoomOut() {
                    if (isMouseDown) return;
                    queueZoom = setTimeout(function () {
                        rail.css({ "width": o.size });
                        bar.css({ "width": o.size });
                    }, 1000);
                }

                // check start position
                if (o.start == 'bottom') {
                    // scroll content to bottom
                    bar.css({ top: me.outerHeight() - bar.outerHeight() });
                    scrollContent(0, true);
                }
                else if (typeof o.start == 'object') {
                    // scroll content
                    scrollContent($(o.start).position().top, null, true);

                    // make sure bar stays hidden
                    if (!o.alwaysVisible) { bar.hide(); }
                }
            });

            // maintain chainability
            return this;
        }
    });

    jQuery.fn.extend({
        slimscroll: jQuery.fn.slimScrollCustom
    });

})(jQuery);
